package taskhandler

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/xuri/excelize/v2"

	"cvevulner/common"
	"cvevulner/models"
	"cvevulner/util"
)

var localLock sync.Mutex

type GitInfo struct {
	StartTime string
	Token     string
	Owner     string
}

type CveBranch struct {
	CveNums   []string
	BranchMap map[string][]string
}

type CveComponent struct {
	PackMap map[string]CveBranch
}

// Handling openGauss data types
func GaussUnaffectIssue(branchVersion []string, gi GitInfo) {
	for _, bv := range branchVersion {
		data, gdErr := models.QueryGaussIssueData(gi.StartTime)
		if len(data) > 0 {
			for _, v := range data {
				ogc := models.OpenGaussCveList{CveNum: v.CveNum, PackName: v.OwnedComponent, Status: 3}
				ogcErr := models.QueryReleaseCve(&ogc, "CveNum", "PackName", "Status")
				if ogc.Id > 0 {
					var center models.VulnCenter
					center.CveId = v.CveId
					center.OrganizationID = 2
					centErr := models.GetVulnCenterByCid(&center, "CveId", "OrganizationID")
					if centErr == nil {
						center.IsExport = 1
						models.UpdateVulnCenter(&center, "is_export")
					}
					continue
				} else {
					logs.Info("Continue to execute data, ogcErr: ", ogcErr)
				}
				// Get specific business data
				el, gsErr := models.QueryGaussExportSaData(v.CveNum, v.IssueNum, v.Repo, v.IssueId)
				if gsErr != nil {
					logs.Error("QueryGaussExportSaData, err: ", gsErr, "tpl.CveNum, tpl.IssueNum: ",
						v.CveNum, v.IssueNum, v.OwnedComponent)
					return
				}
				for _, vx := range el {
					affectBool := GaussFindUnaffVersion(&vx, bv, gi)
					if affectBool {
						logs.Info("Unaffected version, data: ", vx.CveNum, vx.OwnedComponent, vx.AffectProduct)
						// Generate unaffected cvrf files
						localLock.Lock()
						UnaffectCveStore(&vx, bv)
						localLock.Unlock()
					}
				}
			}
		} else {
			logs.Error(gdErr)
		}
	}
}

// Does not affect the storage and release of cve data
func UnaffectCveStore(xmlp *models.ExcelExport, versions string) {
	ogc := models.OpenGaussCveList{CveNum: xmlp.CveNum, PackName: xmlp.OwnedComponent}
	ogcErr := models.QueryReleaseCve(&ogc, "CveNum", "PackName")
	if ogc.Id == 0 {
		logs.Info("ogcErr: ", ogcErr, xmlp.CveNum, xmlp.OwnedComponent)
		CreateReleaseCve(&ogc, xmlp, 1, 0)
		ogcId, gocErr := models.InsertReleaseCve(&ogc)
		if ogcId > 0 {
			ogv := models.OpenGaussVersion{CveId: ogcId, CveNum: xmlp.CveNum, RepoVersion: versions}
			verErr := models.QueryGaussVersion(&ogv, "CveId", "CveNum", "RepoVersion")
			if ogv.VersionId == 0 {
				logs.Info("QueryGaussVersion, verErr: ", verErr)
				CreateGaussVersion(&ogv, 1, 2, 2, xmlp.CveNum, versions,
					"Unaffected", ogcId)
				versionId, vErr := models.InsertGaussVersion(&ogv)
				if versionId > 0 {
					logs.Info("InsertGaussVersion, Data inserted successfully, id: ", versionId)
				} else {
					logs.Error("InsertGaussVersion, Data insertion failed, err: ", vErr, ogv)
				}
			} else {
				gv := CreateGaussVersion(&ogv, 2, 2, 2, xmlp.CveNum, versions,
					"Unaffected", ogcId)
				uvErr := models.UpdateGaussVersion(&ogv, gv...)
				logs.Info("UpdateGaussVersion, uvErr: ", uvErr)
			}
		} else {
			logs.Error("InsertReleaseCve, gocErr: ", gocErr)
			return
		}
	} else {
		updateSlice := CreateReleaseCve(&ogc, xmlp, 2, 0)
		upErr := models.UpdateReleaseCve(&ogc, updateSlice...)
		if upErr == nil {
			ogv := models.OpenGaussVersion{CveId: ogc.Id, CveNum: xmlp.CveNum, RepoVersion: versions}
			verErr := models.QueryGaussVersion(&ogv, "CveId", "CveNum", "RepoVersion")
			if ogv.VersionId == 0 {
				logs.Info("QueryGaussVersion2, verErr: ", verErr)
				CreateGaussVersion(&ogv, 1, 2, 2, xmlp.CveNum, versions,
					"Unaffected", ogc.Id)
				versionId, vErr := models.InsertGaussVersion(&ogv)
				if versionId > 0 {
					logs.Info("InsertGaussVersion2, Data inserted successfully, id: ", versionId)
				} else {
					logs.Error("InsertGaussVersion2, Data insertion failed, err: ", vErr, ogv)
				}
			} else {
				gv := CreateGaussVersion(&ogv, 2, 2, 2, xmlp.CveNum, versions,
					"Unaffected", ogc.Id)
				uvErr := models.UpdateGaussVersion(&ogv, gv...)
				logs.Info("UpdateGaussVersion2, uvErr: ", uvErr)
			}
		}
	}
}

func CreateGaussVersion(ogv *models.OpenGaussVersion, flag, affectStatus, ReleaseFlag int8,
	cveNum, versions, affectStatusName string, cveId int64) []string {
	gv := make([]string, 0)
	ogv.CveId = cveId
	gv = append(gv, "CveId")
	ogv.CveNum = cveNum
	gv = append(gv, "CveNum")
	ogv.RepoVersion = versions
	gv = append(gv, "RepoVersion")
	ogv.AffectStatusName = affectStatusName
	gv = append(gv, "AffectStatusName")
	ogv.AffectStatus = affectStatus
	gv = append(gv, "AffectStatus")
	ogv.ReleaseFlag = ReleaseFlag
	gv = append(gv, "ReleaseFlag")
	if flag == 2 {
		ogv.UpdateTime = common.GetCurTime()
		gv = append(gv, "UpdateTime")
	} else {
		ogv.CreateTime = common.GetCurTime()
	}
	return gv
}

func CreateReleaseCve(ogc *models.OpenGaussCveList, xmlp *models.ExcelExport, flag int, gaussId int64) []string {
	return nil
}

func GaussFindUnaffVersion(xmlp *models.ExcelExport, versions string, gi GitInfo) bool {
	branchArry, _ := GetBranchesInfo(gi.Token, gi.Owner, xmlp.Repo, 2)
	if len(branchArry) == 0 {
		gaussVersion := beego.AppConfig.String("opengauss::gauss_version")
		if len(gaussVersion) > 0 {
			gaussVerSlice := strings.Split(gaussVersion, ",")
			if len(gaussVerSlice) > 0 {
				branchArry = append(branchArry, gaussVerSlice...)
			}
		}
	}
	affectBool := false
	if xmlp.AffectedVersion != "" && len(xmlp.AffectedVersion) > 1 {
		affSlice := strings.Split(xmlp.AffectedVersion, ",")
		if len(affSlice) > 0 {
			for _, aff := range affSlice {
				if strings.Contains(aff, versions+":") || strings.Contains(aff, versions+"：") {
					branchSlice := make([]string, 0)
					if strings.Contains(aff, ":") {
						branchSlice = strings.Split(aff, ":")
					} else if strings.Contains(aff, "：") {
						branchSlice = strings.Split(aff, "：")
					}
					if len(branchSlice) == 2 {
						if strings.TrimSpace(branchSlice[0]) == versions &&
							len(strings.TrimSpace(branchSlice[1])) > 1 &&
							strings.TrimSpace(branchSlice[1]) != "受影响" {
							// Query branch information
							for _, arr := range branchArry {
								if arr == strings.TrimSpace(branchSlice[0]) {
									affectBool = true
									break
								}
							}
						}
					}
				}
			}
		}
	}
	return affectBool
}

// Download the excel file that needs to be processed and parse the data
func DownloadFileAndParse(fExcel models.OpenGaussDownloadFile, startTime,
	gaussDir string, cveComponent *CveComponent) {
	fileSlice := make([]string, 0)
	if len(fExcel.FilePath) > 1 {
		fileSlice = strings.Split(fExcel.FilePath, "/")
	}
	localPath := filepath.Join(gaussDir, fileSlice[len(fileSlice)-1])
	// Download files from the Internet
	dErr := downloadGaussPackageFile(localPath, fExcel.FilePath)
	if dErr != nil {
		logs.Error(dErr)
		return
	}
	pkgList, err := ReadExcelFile(localPath, fExcel.RepoVersion)
	if err != nil {
		logs.Error(err)
		return
	} else {
		pErr := ParseExcelFile(pkgList, fExcel, startTime, cveComponent)
		if pErr != nil {
			logs.Error(pErr)
		}
	}
}

func ParseExcelFile(pkgList []models.GaussExcelTag, fExcel models.OpenGaussDownloadFile,
	startTime string, cveComponent *CveComponent) error {
	pl := len(pkgList)
	pageSize := 10
	pc := pl / 10
	if pl%10 > 0 {
		pc++
	}
	cd := make(chan []IssueAndPkg)
	start := 0
	end := 0
	for i := 0; i < pc; i++ {
		start = i * pageSize
		end = (i + 1) * pageSize
		if end > pl {
			end = pl
		}
		wgTrigger.Add(1)
		go GuassGetDateByGite(pkgList[start:end], cd, startTime, fExcel.RepoVersion)
	}
	for i := 0; i < pc; i++ {
		wgTrigger.Add(1)
		go GaussHandleGiteData(cd, fExcel, cveComponent)
	}
	wgTrigger.Wait()
	return nil
}

func GaussHandleGiteData(c <-chan []IssueAndPkg, fExcel models.OpenGaussDownloadFile, cveComponent *CveComponent) {
	defer wgTrigger.Done()
	data := <-c
	var pkgList []string
	for _, v := range data {
		pkgList = strings.Split(v.IssuePkg, " ")
		if len(pkgList) == 0 {
			logs.Error("Data is filtered, v.IssuePkg: ", v.IssuePkg)
			continue
		}
		GaussAffectIssue(v, pkgList, fExcel, cveComponent)
	}
}

func GaussAffectIssue(v IssueAndPkg, pkgList []string, fExcel models.OpenGaussDownloadFile, cveComponent *CveComponent) {
	for _, iv := range v.IssueMap {
		tpl := models.IssueTemplate{IssueNum: iv.Number, IssueId: v.IssueId}
		err := models.GetIssueTemplateByColName(&tpl, "issue_num", "issue_id")
		if err != nil {
			logs.Error("GetIssueTemplateByColName, ----", err, iv.Number, v.Repo, v.IssueId)
			continue
		}
		//save data to db
		el, err := models.QueryGaussExportSaData(tpl.CveNum, tpl.IssueNum, tpl.Repo, tpl.IssueId)
		if err != nil {
			logs.Error("QueryGaussExportSaData, err: ", err, "tpl.CveNum, tpl.IssueNum: ",
				tpl.CveNum, tpl.IssueNum, tpl.OwnedComponent)
			continue
		}
		err = GaussHandleContentToDbSync(el, pkgList, fExcel, cveComponent)
		if err != nil {
			logs.Error("GaussHandleContentToDbSync, err: ", err)
		}
	}
}

func GaussHandleContentToDbSync(list []models.ExcelExport, pkgList []string,
	fExcel models.OpenGaussDownloadFile, cveComponent *CveComponent) (err error) {
	lz := len(list)
	if lz > 0 {
		for _, v := range list {
			if v.OrganizateId != 2 {
				logs.Error("openEuler, data: ", v)
				continue
			}
			//affectProduct := v.AffectProduct
			affectBool := affectBrachRep(&v, fExcel.RepoVersion)
			if !affectBool {
				logs.Error("Unaffected version, data: ", v)
				continue
			}
			localLock.Lock()
			AddSaToDb(v, fExcel.RepoVersion, pkgList, cveComponent)
			localLock.Unlock()
		}
	}
	return nil
}

func AddSaToDb(v models.ExcelExport, affectBranch string, pkgList []string, cveComponent *CveComponent) {
	if v.PublicDate == "" {
		v.PublicDate = time.Now().Format("2006-01-02")
	}
	gaussTempId := int64(0)
	ogl := models.OpenGaussListTemp{InfluenceComponent: v.OwnedComponent, AffectProduct: affectBranch}
	oErr := models.QuerySaDataByPackName(&ogl)
	if ogl.GaussTempId > 0 {
		gaussTempId = ogl.GaussTempId
		oglSlice := CreateSaData(v, &ogl, affectBranch)
		uErr := models.UpdateSaData(&ogl, oglSlice...)
		if uErr != nil {
			logs.Error("UpdateSaData, uErr: ", uErr)
		}
	} else {
		logs.Info("QuerySaDataByPackName, err: ", oErr)
		CreateSaData(v, &ogl, affectBranch)
		id, iErr := models.InsertSaData(&ogl)
		if id > 0 {
			gaussTempId = id
			prErr := ParseRpmPackage(pkgList, gaussTempId, v.OwnedComponent, v.PublicDate, affectBranch)
			if prErr != nil {
				logs.Error("ParseRpmPackage, prErr: ", prErr)
			}
		} else {
			logs.Error("InsertSaData, iErr: ", iErr)
		}
	}
	AffectCveStore(&v, affectBranch, gaussTempId)
	// Global data store
	GlobalStoreData(v, affectBranch, cveComponent)
}

// store cve info
func GlobalStoreData(v models.ExcelExport, affectBranch string, cveComponent *CveComponent) {
	if cveComponent.PackMap != nil && len(cveComponent.PackMap) > 0 {
		cb, ok := cveComponent.PackMap[v.OwnedComponent]
		if ok {
			if len(cb.CveNums) > 0 {
				cveFlag := false
				for _, cn := range cb.CveNums {
					if cn == v.CveNum {
						cveFlag = true
						break
					}
				}
				if !cveFlag {
					cb.CveNums = append(cb.CveNums, v.CveNum)
				}
			} else {
				cb.CveNums = make([]string, 0)
				cb.CveNums = append(cb.CveNums, v.CveNum)
			}
			if len(cb.BranchMap) > 0 {
				af, afOk := cb.BranchMap[affectBranch]
				if afOk {
					if len(af) > 0 {
						cfFlag := false
						for _, ch := range af {
							if ch == v.CveNum {
								cfFlag = true
								break
							}
						}
						if !cfFlag {
							af = append(af, v.CveNum)
							cb.BranchMap[affectBranch] = af
						}
					} else {
						af = make([]string, 0)
						af = append(af, v.CveNum)
						cb.BranchMap[affectBranch] = af
					}
				} else {
					af = make([]string, 0)
					af = append(af, v.CveNum)
					cb.BranchMap[affectBranch] = af
				}
			} else {
				cb.BranchMap = make(map[string][]string)
				af := make([]string, 0)
				af = append(af, v.CveNum)
				cb.BranchMap[affectBranch] = af
			}
			cveComponent.PackMap[v.OwnedComponent] = cb
		} else {
			cveNums := make([]string, 0)
			cveNums = append(cveNums, v.CveNum)
			branchMap := make(map[string][]string)
			branchMap[affectBranch] = cveNums
			var cb CveBranch
			cveNums1 := make([]string, 0)
			cveNums1 = append(cveNums1, v.CveNum)
			cb.CveNums = cveNums1
			cb.BranchMap = branchMap
			cveComponent.PackMap[v.OwnedComponent] = cb
		}
	} else {
		cveNums := make([]string, 0)
		cveNums = append(cveNums, v.CveNum)
		branchMap := make(map[string][]string)
		branchMap[affectBranch] = cveNums
		var cb CveBranch
		cveNums1 := make([]string, 0)
		cveNums1 = append(cveNums1, v.CveNum)
		cb.CveNums = cveNums1
		cb.BranchMap = branchMap
		packMap := make(map[string]CveBranch)
		packMap[v.OwnedComponent] = cb
		cveComponent.PackMap = packMap
	}
}

func AddCveAffectProduct(cveNum, versions string, cveId int64) {
	models.DeleteGaussVersionByIdStatus(cveId)
	ogv := models.OpenGaussVersion{CveId: cveId, CveNum: cveNum, RepoVersion: versions}
	CreateGaussVersion(&ogv, 1, 1, 1, cveNum, versions, "Fixed", cveId)
	versionId, vErr := models.InsertGaussVersion(&ogv)
	if versionId > 0 {
		logs.Info("AffectCveStore, InsertGaussVersion, Data inserted successfully, id: ", versionId)
	} else {
		logs.Error("AffectCveStore, InsertGaussVersion, Data insertion failed, err: ", vErr, ogv)
	}
}

// Does affect the storage and release of cve data
func AffectCveStore(xmlp *models.ExcelExport, versions string, gaussTempId int64) {
	ogc := models.OpenGaussCveList{CveNum: xmlp.CveNum, PackName: xmlp.OwnedComponent}
	ogcErr := models.QueryReleaseCve(&ogc)
	if ogc.Id == 0 {
		logs.Error(ogcErr)
		CreateReleaseCve(&ogc, xmlp, 1, gaussTempId)
		ogcId, gocErr := models.InsertReleaseCve(&ogc)
		if ogcId > 0 {
			AddCveAffectProduct(xmlp.CveNum, versions, ogcId)
		} else {
			logs.Error("AffectCveStore, InsertReleaseCve, gocErr: ", gocErr)
			return
		}
	} else {
		updateSlice := CreateReleaseCve(&ogc, xmlp, 2, gaussTempId)
		upErr := models.UpdateReleaseCve(&ogc, updateSlice...)
		if upErr == nil {
			AddCveAffectProduct(xmlp.CveNum, versions, ogc.Id)
		}
	}
}

func CreateSaData(v models.ExcelExport, ogl *models.OpenGaussListTemp, affectBranch string) []string {
	oglSlice := make([]string, 0)
	if !strings.Contains(ogl.CveNums, v.CveNum) {
		ogl.CveNums = ogl.CveNums + ";" + v.CveNum
		oglSlice = append(oglSlice, "CveNums")
	} else {
		return oglSlice
	}
	ogl.AffectProduct = affectBranch
	ogl.InfluenceComponent = v.OwnedComponent
	ogl.PublicDate = v.PublicDate
	oglSlice = append(oglSlice, "PublicDate")
	ogl.Status = 1
	oglSlice = append(oglSlice, "Status")
	if ogl.GaussTempId > 0 {
		ogl.UpdateTime = common.GetCurTime()
		oglSlice = append(oglSlice, "UpdateTime")
		dSplit := strings.Split(v.Description, "Security Fix(es):")
		if len(dSplit) > 1 {
			if !strings.Contains(ogl.Description, dSplit[0]) {
				ogl.Description = dSplit[0] + ogl.Description
			}
			ogl.Description += dSplit[1]
		}
		oglSlice = append(oglSlice, "Description")
		if ogl.CveLevelValue > 0 {
			switch strings.ToLower(v.CveLevel) {
			case "critical":
				if ogl.CveLevelValue > 1 {
					ogl.CveLevelValue = 1
					ogl.CveLevel = v.CveLevel
				}
			case "high":
				if ogl.CveLevelValue > 2 {
					ogl.CveLevelValue = 2
					ogl.CveLevel = v.CveLevel
				}
			case "medium":
				if ogl.CveLevelValue > 3 {
					ogl.CveLevelValue = 3
					ogl.CveLevel = v.CveLevel
				}
			default:
				ogl.CveLevelValue = 4
				ogl.CveLevel = v.CveLevel
			}
		} else {
			switch strings.ToLower(v.CveLevel) {
			case "critical":
				ogl.CveLevelValue = 1
			case "high":
				ogl.CveLevelValue = 2
			case "medium":
				ogl.CveLevelValue = 3
			default:
				ogl.CveLevelValue = 4
			}
			ogl.CveLevel = v.CveLevel
		}
		oglSlice = append(oglSlice, "CveLevelValue")
		oglSlice = append(oglSlice, "CveLevel")
		theme, err := models.GetGaussExportThem(ogl.CveNums, v.OwnedComponent, affectBranch)
		if err == nil && len(theme) > 1 {
			ogl.Theme = theme
		}
		oglSlice = append(oglSlice, "Theme")
	} else {
		ogl.CreateTime = common.GetCurTime()
		ogl.Description = v.Description
		ogl.CveLevel = v.CveLevel
		switch strings.ToLower(v.CveLevel) {
		case "critical":
			ogl.CveLevelValue = 1
		case "high":
			ogl.CveLevelValue = 2
		case "medium":
			ogl.CveLevelValue = 3
		default:
			ogl.CveLevelValue = 4
		}
		ogl.Summary = v.Summary
		oglSlice = append(oglSlice, "Summary")
		ogl.Introduction = v.Introduction
		oglSlice = append(oglSlice, "Introduction")
		ogl.Theme = v.Theme
		ogl.CveNums = v.CveNum
	}
	ogl.Theme = strings.ReplaceAll(ogl.Theme, "openEuler", "openGauss")
	return oglSlice
}

func ParseRpmPackage(pkgList []string, gaussTempId int64, packageName, publicDate, affectBranch string) error {
	if len(pkgList) > 0 {
		for _, pg := range pkgList {
			pgSlice := strings.Split(pg, ".")
			if len(pgSlice) < 3 {
				logs.Error("ParseRpmPackage, rpm package structure error, pg: ", pg)
				continue
			}
			groupId := int64(0)
			ogg := models.OpenGaussGroup{GroupName: pgSlice[len(pgSlice)-2]}
			gErr := models.QueryOpenGaussGroup(&ogg, "GroupName")
			if ogg.GroupId == 0 {
				ogg.GroupName = pgSlice[len(pgSlice)-2]
				ogg.CreateTime = common.GetCurTime()
				ogg.Status = 1
				id, iErr := models.InsertOpenGaussGroup(&ogg)
				if iErr != nil {
					logs.Error("InsertOpenGaussGroup, err:", iErr)
					continue
				}
				groupId = id
			} else {
				groupId = ogg.GroupId
				logs.Info(gErr)
			}
			platId := int64(0)
			ogp := models.OpenGaussPlatform{PlatName: pgSlice[len(pgSlice)-1]}
			pErr := models.QueryOpenGaussPlatform(&ogp, "PlatName")
			if ogp.PlatId == 0 {
				ogp.PlatName = pgSlice[len(pgSlice)-1]
				ogp.Status = 1
				ogp.CreateTime = common.GetCurTime()
				id, iErr := models.InsertOpenGaussPlatform(&ogp)
				if iErr != nil {
					logs.Error("InsertOpenGaussPlatform, err:", iErr)
					continue
				}
				platId = id
			} else {
				platId = ogp.PlatId
				logs.Info(pErr)
			}
			rpmName := strings.Join(pgSlice[:len(pgSlice)-2], ".")
			ogk := models.OpenGaussPackage{GroupId: groupId, PlatId: platId,
				GaussId: gaussTempId, PackageName: packageName, RpmName: rpmName, RepoVersion: affectBranch}
			opErr := models.QueryOpenGaussPackage(&ogk, "GroupId", "PlatId", "GaussId", "PackageName", "RpmName", "RepoVersion")
			if ogk.PackId > 0 {
				ogk.Status = 1
				ogk.ReleaseDate = publicDate
				ogk.UpdateTime = common.GetCurTime()
				upErr := models.UpdateOpenGaussPackage(&ogk, "Status", "ReleaseDate", "UpdateTime")
				if upErr != nil {
					logs.Error("UpdateOpenGaussPackage, upErr: ", upErr)
				}
			} else {
				logs.Info("QueryOpenGaussPackage, opErr: ", opErr)
				ogk = models.OpenGaussPackage{GroupId: groupId, PlatId: platId, GaussId: gaussTempId,
					PackageName: packageName, RpmName: rpmName, CreateTime: common.GetCurTime(),
					ReleaseDate: publicDate, Status: 1, RepoVersion: affectBranch}
				packId, ipErr := models.InsertOpenGaussPackage(&ogk)
				if packId == 0 {
					logs.Error("InsertOpenGaussPackage, packId, ipErr: ", packId, ipErr)
				}
			}
		}
	}
	return nil
}

func GuassGetDateByGite(pkgList []models.GaussExcelTag, c chan<- []IssueAndPkg, startTime, affectBranch string) {
	defer wgTrigger.Done()
	owner, token := common.GetOwnerAndToken("", int8(2))
	//gaussIssuePath := beego.AppConfig.String("opengauss::gauss_issue_path")
	st := util.TimeStrToInt(startTime, "2006-01-02")
	chData := make([]IssueAndPkg, 0)
	for _, v := range pkgList {
		rt := util.TimeStrToInt(v.PubTime, "20060102 15-04-05")
		// Query the current issues that need to be dealt with
		issueTemp, err := models.GetGaussIssueNumber(v.Repo)
		if err != nil || issueTemp == nil {
			logs.Info("No need to deal with ", v.Repo)
			continue
		}
		for _, isTemp := range issueTemp {
			//logs.Info("isTemp===>", isTemp)
			var prList []models.PullRequestIssue
			prList = getGaussRepoIssueAllPR(affectBranch, token, owner, isTemp.Repo, st, rt, isTemp)
			//prList := getGaussRepoIssueAllPR(affectBranch, token, owner, gaussIssuePath, st, rt, isTemp)
			//get pull request related issue
			repoIssue := make(map[int64]models.PullRequestIssue, 0)
			for _, p := range prList {
				//getPRRelatedAllIssue(token, owner, v.Repo, st, rt, p.Number, repoIssue)
				p.Repo = v.Repo
				repoIssue[p.Id] = p
			}
			if len(repoIssue) > 0 {
				chData = append(chData, IssueAndPkg{IssueMap: repoIssue, IssuePkg: v.Packages,
					Repo: v.Repo, IssueId: isTemp.IssueId})
			}
		}
	}
	c <- chData
}

func getGaussRepoIssueAllPR(affectBranch, token, owner, repo string, startTime,
	releaseTime int64, isTemp models.IssueTemplate) (prList []models.PullRequestIssue) {
	url := fmt.Sprintf("https://gitee.com/api/v5/repos/%v/issues/%v/pull_requests", owner, isTemp.IssueNum)
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		logs.Error("NewRequest, url: ", url, ",err: ", err)
		return
	}
	q := req.URL.Query()
	q.Add("access_token", token)
	q.Add("repo", repo)
	req.URL.RawQuery = q.Encode()
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		logs.Error("DefaultClient, url: ", url, ",err: ", err)
		return
	}
	if resp.StatusCode == http.StatusOK {
		issuePr := make([]map[string]interface{}, 0)
		read, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logs.Error("ReadAll, url: ", url, ",err: ", err)
			return
		}
		logs.Info("getGaussRepoIssueAllPR, value: ", string(read))
		resp.Body.Close()
		err = json.Unmarshal(read, &issuePr)
		if err != nil {
			logs.Error("Unmarshal, url: ", url, ",err: ", err)
			return
		}
		for _, v := range issuePr {
			if _, ok := v["id"]; !ok {
				continue
			}
			pr := models.PullRequestIssue{}
			if v["state"].(string) == "merged" && v["mergeable"].(bool) {
				//mt := v["closed_at"].(string).(time.Time).Local().Unix()
				closedAt := v["closed_at"].(string)
				mt := util.TimeStrToInt(closedAt[:19], "2006-01-02T15:04:05")
				mergedAt := v["merged_at"].(string)
				ct := util.TimeStrToInt(mergedAt[:19], "2006-01-02T15:04:05")
				//logs.Info("======>>mt: ", mt, ", startTime: ", startTime, ",releaseTime: ", releaseTime, ":ct:", ct, ",repo:", repo, ", pr: ", v)
				//ct := v["merged_at"].(string).(time.Time).Local().Unix()
				var pt int64
				if mt > 0 && ct > 0 {
					if mt > ct {
						pt = ct
					} else {
						pt = mt
					}
					if pt >= startTime && pt <= releaseTime {
						if v["base"].(map[string]interface{})["label"].(string) == affectBranch {
							pr.Id = int64(v["id"].(float64))
							pr.Number = isTemp.IssueNum
							pr.CveNumber = isTemp.CveNum
							pr.Repo = v["base"].(map[string]interface{})["repo"].(map[string]interface{})["path"].(string)
							pr.Branch = affectBranch
							pr.BrFlag = true
							prList = append(prList, pr)
						}
					}
				}
			}
		}
	} else {
		resp.Body.Close()
	}
	return
}

func downloadGaussPackageFile(localPath, url string) error {
	timeStamp := time.Now().Unix()
	url = url + "?" + strconv.FormatInt(timeStamp, 10)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusOK {
		pkgLock.Lock()
		defer pkgLock.Unlock()
		if ex, _ := util.IsExistPath(localPath); ex {
			err := os.Remove(localPath)
			if err != nil {
				logs.Error(err)
			}
		}
		out, err := os.Create(localPath)
		if err != nil {
			return err
		}
		defer out.Close()
		_, err = io.Copy(out, resp.Body)
		return err
	} else {
		return errors.New("download file request fail")
	}
}

// ReadExcelFile reads an Excel file and extracts package data.
func ReadExcelFile(lp string, versions string) (pkgList []models.GaussExcelTag, err error) {
	pkgLock.Lock()
	defer pkgLock.Unlock()
	if lp == "" || path.Ext(lp) != ".xlsx" {
		return pkgList, errors.New("the file path is error")
	}
	f, opErr := excelize.OpenFile(lp)
	if opErr != nil {
		logs.Error(opErr)
		return pkgList, opErr
	}
	rows, rErr := f.GetRows(versions)
	if rErr != nil {
		logs.Error(rErr)
		return pkgList, rErr
	}
	for _, row := range rows {
		pkgList = append(pkgList, models.GaussExcelTag{PubTime: row[0], Repo: row[1], Packages: row[2]})
	}
	return pkgList, nil
}

// Complete data conversion
func TempCveToGaussCve(tempGaussId int64, ogl []models.OpenGaussCveList) {
	if len(ogl) > 0 {
		for _, ol := range ogl {
			osl := models.OpenGaussCveList{GaussId: tempGaussId, CveNum: ol.CveNum}
			cbErr := models.QueryOpenGaussCveByNum(&osl, "GaussId", "CveNum")
			if cbErr == nil {
				models.UpdateOpenGaussVersionByCid(osl.Id, ol.Id, ol.CveNum)
			}
		}
		models.UpdateOpenGaussPackByGid(tempGaussId, ogl[0].GaussId)
	}
	models.DeleteOpenGaussCveByGid(tempGaussId)
	//models.DeleteOpenGaussPackByGid(tempGaussId)
}

func DeleteGaussCveVaildData(gaussId int64) {
	ogg, oggErr := models.QueryOpenGaussCveByGid(gaussId)
	if len(ogg) > 0 {
		for _, og := range ogg {
			models.DeleteOpenGaussVersionById(og.Id)
		}
		models.DeleteOpenGaussCveByGid(gaussId)
	} else {
		logs.Info("QueryOpenGaussCveByGid, oggErr: ", oggErr, ",GaussId: ", gaussId)
	}
	models.DeleteOpenGaussPackByGid(gaussId)
}

func ClearHisDataSa(flag int) {
	if flag == 2 {
		ogl, oglErr := models.QueryOpenGaussSitePreAll()
		if len(ogl) == 0 {
			logs.Info("ClearHisDataSa, oglErr: ", oglErr)
		} else {
			for _, o := range ogl {
				DeleteGaussCveVaildData(o.GaussId)
			}
			models.DeleteOpenGaussSitePreAll()
		}
	} else {
		ogg, oggErr := models.QueryOpenGaussCveByGid(0)
		if len(ogg) > 0 {
			for _, og := range ogg {
				models.DeleteOpenGaussVersionById(og.Id)
				models.DeleteOpenGaussCveByCid(og.Id)
			}
		} else {
			logs.Info("QueryOpenGaussCveByGid, oggErr: ", oggErr)
		}
	}

}

func PreGeneratedSaData(packName string, bVersionSlice []string, isEque bool, saInitValue *int64) {
	if isEque {
		ogl, ogErr := models.QuerySaTempByPackName(packName)
		if len(ogl) > 0 {
			openGaussNum := "openGauss-SA-" + strconv.Itoa(time.Now().Year()) + "-" + strconv.FormatInt(*saInitValue, 10)
			var osl models.OpenGaussSiteList
			CreateOpenGaussSite(&osl, ogl[0], bVersionSlice, openGaussNum, *saInitValue)
			sitGaussId, gErr := models.InsertOpenGaussSiteList(&osl)
			if sitGaussId > 0 {
				models.UpdateOpenGaussCveByGid(ogl[0].GaussTempId, sitGaussId)
				models.UpdateOpenGaussPackByGid(ogl[0].GaussTempId, sitGaussId)
			} else {
				logs.Error("InsertOpenGaussSiteList, gErr: ", gErr)
				return
			}
			*saInitValue += 1
			// Delete duplicate data
			if len(ogl) > 1 {
				ogg, oggErr := models.QueryOpenGaussCveByGid(sitGaussId)
				if oggErr != nil {
					logs.Error("PreGeneratedSaData, QueryOpenGaussCveByGid, ogErr: ", oggErr)
					return
				}
				for _, l := range ogl[1:] {
					TempCveToGaussCve(l.GaussTempId, ogg)
				}
			}
		} else {
			logs.Error("PreGeneratedSaData, QuerySaTempByPackName, ogErr: ", ogErr)
			return
		}
	} else {
		ogl, ogErr := models.QuerySaTempByPackName(packName)
		if len(ogl) > 0 {
			for _, l := range ogl {
				openGaussNum := "openGauss-SA-" + strconv.Itoa(time.Now().Year()) + "-" + strconv.FormatInt(*saInitValue, 10)
				var osl models.OpenGaussSiteList
				CreateOpenGaussSite(&osl, l, bVersionSlice, openGaussNum, *saInitValue)
				sitGaussId, gErr := models.InsertOpenGaussSiteList(&osl)
				if sitGaussId > 0 {
					models.UpdateOpenGaussCveByGid(l.GaussTempId, sitGaussId)
					models.UpdateOpenGaussPackByGid(l.GaussTempId, sitGaussId)
				} else {
					logs.Error("InsertOpenGaussSiteList, gErr: ", gErr)
					return
				}
				*saInitValue += 1
			}
		} else {
			logs.Error("PreGeneratedSaData, QuerySaTempByPackName2, ogErr: ", ogErr)
			return
		}
	}
	models.DeleteSaTempByPackName(packName)
}

// Reorganize the data
func CreateOpenGaussSite(osl *models.OpenGaussSiteList, olt models.OpenGaussListTemp,
	bVersionSlice []string, openGaussNum string, saInitValue int64) {
	osl.SaNum = saInitValue
	osl.CveNums = olt.CveNums
	osl.PublicDate = olt.PublicDate
	osl.InfluenceComponent = olt.InfluenceComponent
	osl.Status = 1
	osl.CreateTime = common.GetCurTime()
	osl.CveLevelValue = olt.CveLevelValue
	osl.CveLevel = olt.CveLevel
	osl.Description = olt.Description
	if len(bVersionSlice) < 2 {
		osl.Theme = olt.Theme
		osl.Introduction = olt.Introduction
	} else if len(bVersionSlice) == 2 {
		bVersionStr := strings.Join(bVersionSlice, " and ")
		theme := strings.ReplaceAll(olt.Theme, olt.AffectProduct, bVersionStr)
		osl.Theme = theme
		introduction := strings.ReplaceAll(olt.Introduction, olt.AffectProduct, bVersionStr)
		osl.Introduction = introduction
	} else {
		bVersionStr := strings.Join(bVersionSlice[:len(bVersionSlice)-1], ",") + " and " + bVersionSlice[len(bVersionSlice)-1]
		theme := strings.ReplaceAll(olt.Theme, olt.AffectProduct, bVersionStr)
		osl.Theme = theme
		introduction := strings.ReplaceAll(olt.Introduction, olt.AffectProduct, bVersionStr)
		osl.Introduction = introduction
	}
	osl.AffectProduct = strings.Join(bVersionSlice, "/")
	osl.Summary = olt.Summary
	osl.GaussSaNum = openGaussNum
	osl.Years = time.Now().Year()
}
